package com.moralesce.gt.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * A complete set of 52 playing cards.
 * 
 * <p>
 * A deck of cards may be used for playing a great variety of card games, with
 * varying elements of skill and chance, some of which are played for money.
 * </p>
 * 
 * @author Brandon Grenier
 */
public class Deck {

	private final List<Card> cards = new ArrayList<Card>();

	public Deck() {
		for (Suit suit : Suit.values()) {
			for (Rank rank : Rank.values()) {
				cards.add(new Card(rank, suit));
			}
		}
	}

	/**
	 * Shuffles all cards in the deck.
	 * 
	 * @return A shuffled deck.
	 */
	public Deck shuffle() {
		Collections.shuffle(cards);
		return this;
	}

	/**
	 * Returns a list of all cards in the deck.
	 * 
	 * @return A List<Card> of all cards in the deck.
	 */
	public List<Card> cards() {
		return Collections.unmodifiableList(cards);
	}

	/**
	 * Returns the size of the deck.
	 * 
	 * @return The size of the deck.
	 */
	public int size() {
		return cards.size();
	}

	/**
	 * Returns the total number of cards with the given rank in the deck.
	 * 
	 * @param rank The rank.
	 * 
	 * @return The total number of card with the given rank in the deck.
	 */
	public Integer cardsWithRank(Rank rank) {
		Integer count = 0;
		for (Card card : cards) {
			if (card.rank().equals(rank)) {
				count += 1;
			}
		}
		return count;
	}

	/**
	 * Returns the total number of cards with the given suit in the deck.
	 * 
	 * @param suit The suit.
	 * 
	 * @return The total number of card with the given suit in the deck.
	 */
	public Integer cardsWithSuit(Suit suit) {
		Integer count = 0;
		for (Card card : cards) {
			if (card.suit().equals(suit)) {
				count += 1;
			}
		}
		return count;
	}

	/**
	 * Removes the specified card from the deck.
	 * 
	 * @param card The card to remove.
	 * 
	 * @return The deck.
	 */
	public Deck remove(Card card) {
		this.cards.remove(card);
		return this;
	}

	/**
	 * Removes the specified cards from the deck.
	 * 
	 * @param cards The list of cards to remove.
	 * 
	 * @return The deck.
	 */
	public Deck remove(List<Card> cards) {
		this.cards.removeAll(cards);
		return this;
	}

}
